/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.rtx.base.event;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import im.rtx.base.service.EventService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;

/**
 * Project  : im.rtx.base.net
 * Author   : solosky < solosky772@qq.com >
 * Created  : 2014/10/6
 * License  : Apache License 2.0
 */
@Service
public class EventHandlerBeanProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    private static final Logger LOG = LoggerFactory.getLogger(EventHandlerBeanProcessor.class);
    @Resource
    private EventService eventService;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean.getClass().isAnnotationPresent(EventHandler.class)) {
            List<String> events = Lists.newArrayList();
            for (Method m : bean.getClass().getDeclaredMethods()) {
                if (m.isAnnotationPresent(EventHandler.class)) {
                    EventHandler handler = m.getAnnotation(EventHandler.class);
                    String[] eventArray = handler.value();
                    if (eventArray.length > 0) {
                        events.addAll(Lists.newArrayList(eventArray));
                    }
                }
            }
            if (events.size() > 0) {
                eventService.register(events.toArray(new String[]{}), new ProxyEventHandler(bean));
            }
        }
        return super.postProcessAfterInitialization(bean, beanName);
    }


    private static class ProxyEventHandler implements EventListener {
        private Object bean;

        private ProxyEventHandler(Object bean) {
            this.bean = bean;
        }

        @Override
        public void onEvent(Event event) {
            processEvent(bean, event);
        }

        private void processEvent(Object bean, Event event) {
            for (Method m : bean.getClass().getDeclaredMethods()) {
                if (m.isAnnotationPresent(EventHandler.class)) {
                    EventHandler handler = m.getAnnotation(EventHandler.class);
                    String[] codes = handler.value();
                    Set<String> sets = Sets.newHashSet(codes);
                    if (sets.contains(event.getCode())) {
                        try {
                            if(!m.isAccessible()){
                                m.setAccessible(true);
                            }
                            m.invoke(bean, event);
                        } catch (Exception e) {
                            LOG.warn("invoke IMEventHandler Error!! proxyObject={}, net={}", bean, event, e);
                        }
                    }
                }
            }
        }
    }

}
